package net.jcip.chapter2;

import java.math.BigInteger;
import java.util.Random;
import java.util.concurrent.atomic.*;
import javax.servlet.*;

import net.jcip.annotations.*;

/**
 * UnsafeCachingFactorizer : Servlet that attempts to cache its last result without adequate atomicity
 * <p>
 * 我们希望提升性能, 把最近的结果缓存起来; 当 2个连续的请求过来的时候, 可以直接使用上一次的结果;
 * <p>
 * 然而 ,尽管这些原子引用本身都是线程安全的，但在UnsafeCachingFactorizer中存在着竞态条件，这可能产生错误的结果;
 * 在线程安全性的定义中要求，多个线程之间的操作无论采用何种执行时序或交替方式，都要保证不变性条件不被破坏;
 * <p>
 * UnsafeCachingFactorizer 的不变性条件之一是：在lastFactors中 缓存的因数之积应该等于在lastNumber中缓存的数值;
 * 只有确保了这个不变性条件不被破坏，上面的Servlet才是正确的;
 * 当在不变性条件中涉及多个变量时，各个变量之间并不是彼此独立的，而是某个变量的值会对其他变量的值产生约束;
 * 因此，当更新某一个变量时，需要在同一个原子操作中对其他变量同时进行更新;
 *
 * <strong>在某些执行时序中，UnsafeCachingFactorizer可能会破坏这个不变性条件;
 * 在使用原子引用的情况下，尽管对set方法的每次调用都是原子的，但仍然无法同时更新lastNumber和lastFactors; </strong>
 * <p>
 * 如果只修改了其中一个变量，那么在这两次修改操作之间，其他线程将发现不变性条件被破坏了;
 * <p>
 * explanation:  简单点说 哪怕两个原子类, 组合在一起 , 也未必能够 形成一个 原子操作;
 * <p>
 * TODO : 编码证明
 *
 * @author Brian Goetz and Tim Peierls
 */
@NotThreadSafe
public class UnsafeCachingFactorizer extends GenericServlet implements Servlet {

    private final AtomicReference<BigInteger> lastNumber = new AtomicReference<>();
    private final AtomicReference<BigInteger[]> lastFactors = new AtomicReference<>();

    public void service(ServletRequest req, ServletResponse resp) {
        BigInteger i = extractFromRequest(req);  //从  req 中解析 参数
        if (i.equals(lastNumber.get())){         //是否是上一个数字
            encodeIntoResponse(resp, lastFactors.get());  //写入 response
        }
        else {
            BigInteger[] factors = factor(i);
            lastNumber.set(i);                           //写入缓存
            lastFactors.set(factors);
            encodeIntoResponse(resp, factors);     //封装到 response
        }
    }

    private void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) {
        System.out.println("封装 response.....");
    }


    /**
     * 使用一个 随机数来 代替请求
     * */
    private BigInteger extractFromRequest(ServletRequest req) {
        return new BigInteger(new Random().nextInt(100) +"" );
    }

    private BigInteger[] factor(BigInteger i) {
        // Doesn't really factor  只有一个元素的 array
        return new BigInteger[]{i};
    }


    public static void main(String[] args){








    }



}

